/*
 * To change this license header, choose License Headers in Project Properties.
 * To change this template file, choose Tools | Templates
 * and open the template in the editor.
 */
package com.sh.ndt.question.mbean;

import com.sh.ndt.common.CreateXML;
import com.sh.ndt.common.SessionObjects;
import com.sh.ndt.common.URL;
import com.sh.ndt.common.WSCaller;
import com.sh.ndt.exam.entity.ExamSession;
import com.sh.ndt.exam.entity.TestHistoryParam;
import com.sh.ndt.exam.entity.TestSession;
import com.sh.ndt.question.entity.Question;
import com.sh.ndt.question.entity.QuestionParam;
import com.sh.ndt.schedule.entity.ExamScheduleParam;
import com.sh.ndt.user.entity.UserDashboardDetail;
import com.sh.ndt.user.entity.UserEntitlement;
import com.sh.ndt.user.entity.UserParam;
import java.io.IOException;
import java.io.Serializable;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.TreeMap;
import javax.faces.application.FacesMessage;
import javax.faces.bean.ManagedBean;
import javax.faces.bean.SessionScoped;
import javax.faces.context.ExternalContext;
import javax.faces.context.FacesContext;
import javax.faces.event.ActionEvent;
import org.apache.log4j.Logger;
import org.primefaces.component.tabview.TabView;
import org.primefaces.context.RequestContext;
import org.primefaces.event.SelectEvent;

/**
 *
 * @author Prashanth
 */
@ManagedBean(name = "questionBoardBean")
@SessionScoped
public class QuestionBoardBean implements Serializable {


    private static final Logger LOGGER = Logger.getLogger(QuestionBoardBean.class);

    private static final long serialVersionUID = 1L;
    private int maxQuestionCount = 0;
    private long examTimeLimit = 0;

    private TestSession testSession = null;
    private List<Question> questionsList = null;
    private int totalQuestionsCount = 0;
    private int attemptedAnswerCount = 0;
    private int unAnsweredQuestionsCount = 0;
    private int questionsMarkedForReview = 0;
    private QuestionParam questionParam = new QuestionParam();
    private ExamSession examSession = null;
    private List<String> selectedOption = null;
    private String selectedAnswer = null;
    private Question currentQuestion = null;
    private Question previousQuestion = null;
    private Question nextQuestion = null;
    private int questionPositionPointer = 0;
    private Map<Integer, Question> reviewQuestionsList = new HashMap<Integer, Question>();
    private Map<Integer, TestSession> testSessionList = new HashMap<Integer, TestSession>();
    private List<Question> questionsMarkedForReviewList = new ArrayList<Question>();
    private Map<Integer, Question> unAnsweredQuestionsList = new TreeMap<Integer, Question>();
    private List<Question> questionsMarkedAsUnansweredList = new ArrayList<Question>();

    private double totalAveragePercentage = 0.0;
    private double totalPercentageInGeneralExam = 0.0;
    private double totalPercentageInSpecificExam = 0.0;

    private String backgroundColor = "#ffffff";

    private SessionObjects sob = null;

    private String examType = null;
    private long examId = 0;
    private int testId = 0;

    private boolean nextButtonDisabled = false;
    private boolean previousButtonDisabled = false;

    /**
     * Set Button type enabled or disabled based on examination For general
     * enable show formula botton enabled For Specific enable refer open book
     * enabled
     *
     */
    private boolean formulaButtonDisabled = false;
    private boolean referRTTableButtonDisabled = false;
    private boolean referOpenBookButtonDisabled = false;

    public QuestionBoardBean() {
        LOGGER.debug("Initializing QuestionBoardBean......");
        ExternalContext externalContext = FacesContext.getCurrentInstance().getExternalContext();
        SessionObjects sob1 = (SessionObjects) externalContext.getSessionMap().get("SESSION_OBJECT");
        this.setSob(sob1);
        resetPercentageCounters();
    }

    /**
     * @return the testSession
     */
    public TestSession getTestSession() {
        return testSession;
    }

    /**
     * @param testSession the testSession to set
     */
    public void setTestSession(TestSession testSession) {
        this.testSession = testSession;
    }

    /**
     * @return the totalQuestionsCount
     */
    public int getTotalQuestionsCount() {
        return totalQuestionsCount;
    }

    /**
     * @param totalQuestionsCount the totalQuestionsCount to set
     */
    public void setTotalQuestionsCount(int totalQuestionsCount) {
        this.totalQuestionsCount = totalQuestionsCount;
    }

    /**
     * @return the attemptedAnswerCount
     */
    public int getAttemptedAnswerCount() {
        return attemptedAnswerCount;
    }

    /**
     * @param attemptedAnswerCount the attemptedAnswerCount to set
     */
    public void setAttemptedAnswerCount(int attemptedAnswerCount) {
        this.attemptedAnswerCount = attemptedAnswerCount;
    }

    /**
     * @return the unAnsweredQuestionsCount
     */
    public int getUnAnsweredQuestionsCount() {
        return unAnsweredQuestionsCount;
    }

    /**
     * @param unAnsweredQuestionsCount the unAnsweredQuestionsCount to set
     */
    public void setUnAnsweredQuestionsCount(int unAnsweredQuestionsCount) {
        this.unAnsweredQuestionsCount = unAnsweredQuestionsCount;
    }

    /**
     * @return the questionsMarkedForReview
     */
    public int getQuestionsMarkedForReview() {
        return questionsMarkedForReview;
    }

    /**
     * @param questionsMarkedForReview the questionsMarkedForReview to set
     */
    public void setQuestionsMarkedForReview(int questionsMarkedForReview) {
        this.questionsMarkedForReview = questionsMarkedForReview;
    }

    public String toDashBoard() throws IOException {
        LOGGER.debug("SOB::::::::: " + FacesContext.getCurrentInstance().getExternalContext().getSessionMap().get("SESSION_OBJECT"));
        //
        refreshDashboard();
        
        return "registeredUsersDashboard.xhtml?faces-redirect=true";
        //FacesContext.getCurrentInstance().getExternalContext().redirect("registeredUsersDashboard.xhtml");
        
    }

    /**
     * @return the questionsList
     */
    public List<Question> getQuestionsList() {
        return questionsList;
    }

    /**
     * @param questionsList the questionsList to set
     */
    public void setQuestionsList(List<Question> questionsList) {
        this.questionsList = questionsList;
    }

    public void refreshPage() {
        this.setExamId(getSob().getExamId());
        this.setExamType(getSob().getExamType());
        this.setExamTimeLimit(sob.getExamTimeLimit());
        this.initializeQuestionsForDisplay();
        //getQuestionsForGeneralSession();
    }

    public void refreshDashboard() {
        try{
            UserParam userParam = new UserParam();
            userParam.setUserId(sob.getUser().getUserId());
            String  inputXml = CreateXML.generateUserParamXML(userParam);
            LOGGER.debug(inputXml);
            
            LOGGER.debug(".................... New Value is before updating SOB .................... 1");

            WSCaller wsCaller = new WSCaller();
            //userList = wsCaller.callAuthenticateUserWS(WS_URL_VERIFY_USER, inputXml);
            UserDashboardDetail userDashboardDetail = new UserDashboardDetail();
            
            userDashboardDetail = wsCaller.callGetUserDashboardDetailWS(URL.WS_URL_GET_DASHBOARD_DETAIL, inputXml);
            
            System.out.println("User Dashboard Object: " + userDashboardDetail);
            LOGGER.debug(".................... New Value is before updating SOB .................... 2");
            
            /**
             * Update the dashboard details here...
             * This will act as db cache update every time
             */
            SessionObjects sessionObject = this.getSob();
            sessionObject.setUserDashboardDetail(userDashboardDetail);
            
            FacesContext.getCurrentInstance().getExternalContext().getSessionMap().put("SESSION_OBJECT", sessionObject);
            
            LOGGER.debug(".................... New Value is updated to SOB .................... 3");
            
        }catch(Exception ex){
            ex.printStackTrace();
        }
    
    }

    
    /**
     * This method is used to get questions for general session / exam
     */
    public void getQuestionsForGeneralSession() {
        //set current position of question to 1st Question;

        questionPositionPointer = 0;
        LOGGER.debug("Inside getQuestionsForGeneralSession Method:  Calling generateQuestionParamXML...");
        questionParam.setCategoryId(5);
        questionParam.setRowLimit(15);

        String inputXml = null;
        inputXml = CreateXML.generateQuestionParamXML(questionParam);
        LOGGER.debug(inputXml);

        WSCaller wsCaller = new WSCaller();
        try {
            /**
             * Make sure you are emptying the question list before filling with
             * new set of questions
             */
            //questionsList.clear();   
            this.setQuestionsList(null);
            this.setQuestionsList(wsCaller.callGetQuestionsWS(URL.WS_URL_GET_QUESTIONS, inputXml));
            LOGGER.debug("Questions For This Exam: " + questionsList.size());
        } catch (Exception ex) {
            LOGGER.debug(ex);
        }

    }

    public void getQuestionsForSpecificSession() {
        //set current position of question to 1st Question;

        questionPositionPointer = 0;
        LOGGER.debug("Inside getQuestionsForSpecificSession Method:  Calling generateQuestionParamXML...");
        questionParam.setCategoryId(6);
        questionParam.setRowLimit(10);

        String inputXml = null;
        inputXml = CreateXML.generateQuestionParamXML(questionParam);
        LOGGER.debug(inputXml);

        WSCaller wsCaller = new WSCaller();
        try {
            /**
             * Make sure you are emptying the question list before filling with
             * new set of questions
             */
            //questionsList.clear();
            this.setQuestionsList(null);
            this.setQuestionsList(wsCaller.callGetQuestionsWS(URL.WS_URL_GET_QUESTIONS, inputXml));

            LOGGER.debug("Questions For This Exam: " + questionsList.size());

        } catch (Exception ex) {
            LOGGER.debug(ex);
        }

    }

    public void showFormula(ActionEvent actionEvent) {
        Map<String, Object> options = new HashMap<String, Object>();
        options.put("modal", false);
        options.put("draggable", true);
        options.put("resizable", false);
        options.put("contentWidth", 760);
        options.put("width", 800);
        options.put("height", 450);

        RequestContext.getCurrentInstance().openDialog("showFormula", options, null);
    }

    public void showRTTables(ActionEvent actionEvent) {
        Map<String, Object> options = new HashMap<String, Object>();
        options.put("modal", false);
        options.put("draggable", true);
        options.put("resizable", false);
        options.put("contentWidth", 760);
        options.put("width", 800);
        options.put("height", 450);

        RequestContext.getCurrentInstance().openDialog("referRTTables", options, null);
    }

    public void showReference(ActionEvent actionEvent) {
        Map<String, Object> options = new HashMap<String, Object>();
        options.put("modal", false);
        options.put("draggable", true);
        options.put("resizable", false);
        options.put("contentWidth", 760);
        options.put("width", 800);
        options.put("height", 450);

        RequestContext.getCurrentInstance().openDialog("showReference", options, null);
    }

    public String submitAnswers() {
        LOGGER.debug("Inside submit answers method... ");
        LOGGER.debug("Un Answered Count... " + this.getUnAnsweredQuestionsCount());

        Map<String, Object> options = new HashMap<String, Object>();
        options.put("modal", true);
        options.put("draggable", false);
        options.put("resizable", false);
        options.put("contentWidth", 760);
        options.put("width", 800);
        options.put("height", 450);

        
        /**
         * Check if all the questions are answered If answered, then alow them
         * to go specific session or show them correct answers (In case of mock
         * sessions)
         *
         * Inner if conditions inside else bracket is logic to navigate to
         * specific or mock test sessions; in this ExamId = actual exam not mock
         * exam
         */
        if (unAnsweredQuestionsCount != 0) {
            for (Question question : questionsList) {
                if (question.getUserSelectedAnswer() == null || question.getUserSelectedAnswer().isEmpty()) {
                    LOGGER.debug(question.getRownum() + " : " + question.getUserSelectedAnswer());
                    this.getUnAnsweredQuestionsList().put(question.getRownum(), question);
                }
            }

            /**
             * Fill the list used at UI
             */
            questionsMarkedAsUnansweredList.clear();
            questionsMarkedAsUnansweredList.addAll(this.unAnsweredQuestionsList.values());

            /**
             * Show the first question in from the unanswered list of questions
             */
            this.setCurrentQuestion(this.questionsMarkedAsUnansweredList.get(0));
            /**
             * Open the dialog to show unanswered questions
             */
            RequestContext.getCurrentInstance().openDialog("unansweredQuestions", options, null);
        } else {

            if (getSob().getExamId() == 1 && getSob().getExamType().equals("General")) {

                /**
                 * This block is for processing exam activities
                 */
                /**
                 * Reset all the percentage Counters to make sure that whenever
                 * the page is refreshed or called subsequently there are no old
                 * values glued in session
                 */
                resetPercentageCounters();

                setTotalPercentageInGeneralExam(getPercentageOfCorrectAnswers(this.getQuestionsList()));
                
                LOGGER.debug("Total Percentage In General Exam:  " + getTotalPercentageInGeneralExam());
                this.setQuestionsList(null);
                this.unAnsweredQuestionsList.clear();
                this.testSessionList.clear();
                this.attemptedAnswerCount = 0;
                if (getTotalPercentageInGeneralExam() < 70.0) {
                    markAsFailed();
                    RequestContext.getCurrentInstance().execute("cannotTakeSpecificSessionDlg.show()");
                } else {
                    RequestContext.getCurrentInstance().execute("specificSessionDlg.show()");
                }
            } else if (getSob().getExamId() == 1 && getSob().getExamType().equals("Specific")) {
                /**
                 * This block is for processing exam activities
                 */

                setTotalPercentageInSpecificExam(getPercentageOfCorrectAnswers(this.getQuestionsList()));
                LOGGER.debug("Total Percentage In General Exam:  " + getTotalPercentageInGeneralExam());
                LOGGER.debug("Total Percentage In Specific Exam:  " + getTotalPercentageInSpecificExam());

                setTotalAveragePercentage((getTotalPercentageInGeneralExam() + getTotalPercentageInSpecificExam()) / 2);
                LOGGER.debug("Total Percentage from both exam: " + getTotalAveragePercentage());

                if (getTotalPercentageInSpecificExam() < 70.0) {
                    markAsFailed();
                    RequestContext.getCurrentInstance().execute("examNotPassedDlg.show()");
                } else if (getTotalAveragePercentage() < 80.0) {
                    markAsFailed();
                    RequestContext.getCurrentInstance().execute("examNotPassedDlg.show()");
                } else {
                    LOGGER.debug("End of Examination.........");
                    markAsPassed();
                    RequestContext.getCurrentInstance().execute("endOfExamDlg.show()");
                }

            } else {

                /**
                 * This block is for processing mock test
                 */
                updateMockSession();
                return "showCorrectAnswers.xhtml?faces-redirect=true";
            }

        }
        return null;
    }

    public void reviewQuestions(ActionEvent actionEvent) {
        LOGGER.debug("Inside reviewQuestions method... ");

        LOGGER.debug("getQuestionsMarkedForReviewList: " + this.getQuestionsMarkedForReviewList());
        LOGGER.debug("getReviewQuestionsList: " + this.getReviewQuestionsList().values());

        if (this.questionsMarkedForReview <= 0) {
            FacesContext.getCurrentInstance().addMessage(null, new FacesMessage(FacesMessage.SEVERITY_ERROR, "Message", "There are no questions marked for review"));
            return;
        }

        /**
         * Empty all the continer first
         */
        this.getQuestionsMarkedForReviewList().clear();

        /**
         * Add the questions marked for review
         */
        this.getQuestionsMarkedForReviewList().addAll(this.getReviewQuestionsList().values());

        /**
         * Assign the values to the list
         */
        this.setQuestionsMarkedForReviewList(
                this.questionsMarkedForReviewList);

        /**
         * Set the first question in review list
         */
        this.setCurrentQuestion(
                this.getQuestionsMarkedForReviewList().get(0));
        /**
         * Mark this question as reviewed... False: will indicate, reviewed
         * Otherwise, your first question will always be shown as checked for
         * review in review list.
         */

        this.getCurrentQuestion().setMarkedForReview(false);
        markQuestionForReview();

        /**
         * Open the dialog
         */
        Map<String, Object> options = new HashMap<String, Object>();

        options.put("modal", true);
        options.put("draggable", false);
        options.put("resizable", false);
        options.put("contentWidth", 760);
        options.put("width", 800);
        options.put("height", 450);
        RequestContext.getCurrentInstance().openDialog("questionsForReview", options, null);
    }

    /**
     * @return the examSession
     */
    public ExamSession getExamSession() {
        return examSession;
    }

    /**
     * @param examSession the examSession to set
     */
    public void setExamSession(ExamSession examSession) {
        this.examSession = examSession;
    }

    public void getNextReviewQuestion(ActionEvent event) {
        LOGGER.debug("Next Review Question: Pointer: " + (Integer) event.getComponent().getAttributes().get("action"));
        /**
         * Set the first question in review list Get rownum - 1 position
         */
        this.setCurrentQuestion(this.getQuestionsList().get(((Integer) event.getComponent().getAttributes().get("action")) - 1));

        /**
         * As and when you visit, mark these questions as reviewed
         */
        this.getCurrentQuestion().setMarkedForReview(false);
        markQuestionForReview();
    }

    public void getNextUnAnsweredQuestion(ActionEvent event) {
        LOGGER.debug("Next Unanswered Question: Pointer: " + (Integer) event.getComponent().getAttributes().get("rownum"));
        /**
         * Set the first question in review list Get rownum - 1 position
         */
        this.setCurrentQuestion(this.getQuestionsList().get(((Integer) event.getComponent().getAttributes().get("rownum")) - 1));
        this.setBackgroundColor("#DC8700");

    }

    public void markAnswer() {
        LOGGER.debug("Selected Value: " + this.selectedOption);
        LOGGER.debug("Selected Answer: " + this.getCurrentQuestion().getUserSelectedAnswer());

        /**
         * First go to the appropriate row, or element This is done by getting
         * appropriate row number from the current question - 1 Second Update
         * user selected answer variable inside the question list collection
         * List<Question>
         */
        this.questionsList.get(getCurrentQuestion().getRownum() - 1).setUserSelectedAnswer(this.getCurrentQuestion().getUserSelectedAnswer());

        /**
         * Update the new modified list to reflect on the screen / view
         */
        this.setQuestionsList(this.questionsList);

        //LOGGER.debug("Row Number: " + getCurrentQuestion().getRownum() + " : " + this.getQuestionsList().get(getCurrentQuestion().getRownum()).getUserSelectedAnswer());
        LOGGER.debug("Row Number - 1: " + (getCurrentQuestion().getRownum() - 1) + " : " + this.getQuestionsList().get(getCurrentQuestion().getRownum() - 1).getUserSelectedAnswer());

        this.markAnsweredQuestions();

        /**
         * Remove answered question
         */
        if (this.unAnsweredQuestionsList.containsKey(getCurrentQuestion().getRownum())) {
            this.unAnsweredQuestionsList.remove(getCurrentQuestion().getRownum());
        }

    }

    private void markAnsweredQuestions() {
        /**
         * Mark all the attempted questions Create test session as we add
         * question to session
         */
        TestSession ts = new TestSession();
        ts.setExamId(1);
        ts.setQuestionId(this.getCurrentQuestion().getQuestionId());
        ts.setSelectedOption(this.getCurrentQuestion().getUserSelectedAnswer());
        ts.setUserId(5);

        this.testSessionList.put(this.getCurrentQuestion().getRownum(), ts);

        /**
         * Update Answered Question Count Total test session objects will
         * provide the answered count
         */
        this.setAttemptedAnswerCount(testSessionList.size());

        /**
         * Update Unanswered Question Count
         */
        this.setUnAnsweredQuestionsCount(this.getTotalQuestionsCount() - this.getAttemptedAnswerCount());
        if (this.getUnAnsweredQuestionsCount() == 0) {
            FacesContext.getCurrentInstance().addMessage(null, new FacesMessage(FacesMessage.SEVERITY_INFO, "Test Completion Message", "You have answered all the questions in this section. To submit answers, please click on 'Submit Your Answers Now'"));
        }
    }

    public void markQuestionForReview() {
        LOGGER.debug("Row Number: " + getCurrentQuestion().getRownum());
        LOGGER.debug("Question Id: " + getCurrentQuestion().getQuestionId());
        LOGGER.debug("Review Status: " + getCurrentQuestion().isMarkedForReview());

        /**
         * Mark Question for review only when the check box is checked Check Box
         * Checked: True Check Box UnChecked: False
         */
        if (getCurrentQuestion().isMarkedForReview()) {
            this.reviewQuestionsList.put(this.getCurrentQuestion().getRownum(), this.getCurrentQuestion());
        } else {
            this.reviewQuestionsList.remove(this.getCurrentQuestion().getRownum());
        }

        /**
         * Use the size of the stack to determine questions marked for review
         */
        this.setQuestionsMarkedForReview(this.reviewQuestionsList.size());
    }

    public void onReviewQuestionDialogClose(SelectEvent event) {
        LOGGER.debug("****************** Review Question Dialog Closed ******************");
    }

    public void onUnAnsweredQuestionDialogClose(SelectEvent event) {
        LOGGER.debug("****************** UnAnswered Questions Dialog Closed ******************");
        this.unAnsweredQuestionsList.clear();
        this.setUnAnsweredQuestionsList(unAnsweredQuestionsList);
    }

    public void closeReviewQuestionDialog() {
        RequestContext.getCurrentInstance().closeDialog("questionsForReview");
    }

    public void closeUnAnsweredQuestionDialog() {
        RequestContext.getCurrentInstance().closeDialog("unansweredQuestions");
    }

    /**
     * @return the selectedOption
     */
    public List<String> getSelectedOption() {
        return selectedOption;
    }

    /**
     * @param selectedOption the selectedOption to set
     */
    public void setSelectedOption(List<String> selectedOption) {
        this.selectedOption = selectedOption;
    }

    /**
     * @return the selectedAnswer
     */
    public String getSelectedAnswer() {
        return selectedAnswer;
    }

    /**
     * @param selectedAnswer the selectedAnswer to set
     */
    public void setSelectedAnswer(String selectedAnswer) {
        this.selectedAnswer = selectedAnswer;
    }

    private TabView tabView;

    public TabView getTabView() {
        return tabView;
    }

    public void setTabView(TabView tabView) {
        this.tabView = tabView;
    }

    public void getPreviousQuestion(ActionEvent actionEvent) {
        LOGGER.debug("Inside getPreviousQuestion" + getCurrentQuestion().getRownum());

        questionPositionPointer = questionPositionPointer - 1;
        if (questionPositionPointer > -1) {
            this.setCurrentQuestion(this.getQuestionsList().get(questionPositionPointer));
            setPreviousButtonDisabled(false);
            setNextButtonDisabled(false);
        } else {
            questionPositionPointer = 0;
            setPreviousButtonDisabled(true);
            setNextButtonDisabled(false);
        }

    }

    public void getNextQuestion(ActionEvent actionEvent) {
        LOGGER.debug("Inside getNextQuestion" + getCurrentQuestion().getRownum());

        questionPositionPointer = questionPositionPointer + 1;
        if (questionPositionPointer < this.getMaxQuestionCount()) {
            this.setCurrentQuestion(this.getQuestionsList().get(questionPositionPointer));
            setNextButtonDisabled(false);
            setPreviousButtonDisabled(false);
        } else {
            questionPositionPointer = this.getMaxQuestionCount() - 1;
            setNextButtonDisabled(true);
            setPreviousButtonDisabled(false);
        }
    }

    /**
     * @return the currentQuestion
     */
    public Question getCurrentQuestion() {
        return currentQuestion;
    }

    /**
     * @param currentQuestion the currentQuestion to set
     */
    public void setCurrentQuestion(Question currentQuestion) {
        this.currentQuestion = currentQuestion;
    }

    /**
     * @return the reviewQuestionsList
     */
    public Map<Integer, Question> getReviewQuestionsList() {
        return reviewQuestionsList;
    }

    /**
     * @param reviewQuestionsList the reviewQuestionsList to set
     */
    public void setReviewQuestionsList(Map<Integer, Question> reviewQuestionsList) {
        this.reviewQuestionsList = reviewQuestionsList;
    }

    /**
     * @return the testSessionList
     */
    public Map<Integer, TestSession> getTestSessionList() {
        return testSessionList;
    }

    /**
     * @param testSessionList the testSessionList to set
     */
    public void setTestSessionList(Map<Integer, TestSession> testSessionList) {
        this.testSessionList = testSessionList;
    }

    /**
     * @return the questionsMarkedForReviewList
     */
    public List<Question> getQuestionsMarkedForReviewList() {
        return questionsMarkedForReviewList;
    }

    /**
     * @param questionsMarkedForReviewList the questionsMarkedForReviewList to
     * set
     */
    public void setQuestionsMarkedForReviewList(List<Question> questionsMarkedForReviewList) {
        this.questionsMarkedForReviewList = questionsMarkedForReviewList;
    }

    /**
     * @return the unAnsweredQuestionsList
     */
    public Map<Integer, Question> getUnAnsweredQuestionsList() {
        for (Map.Entry entry : this.unAnsweredQuestionsList.entrySet()) {
            //This will sort the map;
        }
        return unAnsweredQuestionsList;
    }

    /**
     * @param unAnsweredQuestionsList the unAnsweredQuestionsList to set
     */
    public void setUnAnsweredQuestionsList(Map<Integer, Question> unAnsweredQuestionsList) {
        this.unAnsweredQuestionsList = unAnsweredQuestionsList;
    }

    /**
     * @return the questionsMarkedAsUnansweredList
     */
    public List<Question> getQuestionsMarkedAsUnansweredList() {
        return questionsMarkedAsUnansweredList;
    }

    /**
     * @param questionsMarkedAsUnansweredList the
     * questionsMarkedAsUnansweredList to set
     */
    public void setQuestionsMarkedAsUnansweredList(List<Question> questionsMarkedAsUnansweredList) {
        this.questionsMarkedAsUnansweredList = questionsMarkedAsUnansweredList;
    }

    public void freezeActivities(ActionEvent event) {
        LOGGER.debug("************** Freezing the activities **************");
        RequestContext.getCurrentInstance().execute("freezeDlg.show()");
    }

    public void firstAlert(ActionEvent event) {
        LOGGER.debug("************** Freezing the activities **************");
        FacesMessage message = new FacesMessage(FacesMessage.SEVERITY_INFO, "Time Alert", "Your session is going to end in another 10 minutes...");
        RequestContext.getCurrentInstance().showMessageInDialog(message);
    }

    public void secondAlert(ActionEvent event) {
        LOGGER.debug("************** Freezing the activities **************");
        FacesMessage message = new FacesMessage(FacesMessage.SEVERITY_INFO, "Time Alert", "Your session is going to end in another 5 minutes...");
        RequestContext.getCurrentInstance().showMessageInDialog(message);
    }

    /**
     * @return the examType
     */
    public String getExamType() {
        return examType;
    }

    /**
     * @param examType the examType to set
     */
    public void setExamType(String examType) {
        this.examType = examType;
    }

    /**
     * @return the examId
     */
    public long getExamId() {
        return examId;
    }

    /**
     * @param examId the examId to set
     */
    public void setExamId(long examId) {
        this.examId = examId;
    }

    /**
     * @return the sob
     */
    public SessionObjects getSob() {
        return sob;
    }

    /**
     * @param sob the sob to set
     */
    private void setSob(SessionObjects sob) {
        this.sob = sob;
    }

    /**
     * @return the examTimeLimit
     */
    public long getExamTimeLimit() {
        return examTimeLimit;
    }

    /**
     * @param examTimeLimit the examTimeLimit to set
     */
    public void setExamTimeLimit(long examTimeLimit) {
        this.examTimeLimit = examTimeLimit;
    }

    private double getPercentageOfCorrectAnswers(List<Question> questionsList) {

        double totalQuestions = questionsList.size();
        double totalCorrectAnswers = 0.0;
        LOGGER.debug("**********************************************");
        LOGGER.debug("Total Questions : " + totalQuestions);
        /**
         * Calculate the count of correct answers.
         */
        for (Question qn : questionsList) {
            if (qn.getAnswer().equals(qn.getUserSelectedAnswer())) {
                LOGGER.debug("Actual - " + qn.getAnswer() + " : User Answered - " + qn.getUserSelectedAnswer());
                totalCorrectAnswers++;
            }
        }
        LOGGER.debug("Total Correct Answers : " + totalCorrectAnswers);

        double percentageOfCorrectAnswers = (totalCorrectAnswers / totalQuestions) * 100;
        LOGGER.debug("Total % of Correct Answers : " + percentageOfCorrectAnswers);
        LOGGER.debug("**********************************************");

        return percentageOfCorrectAnswers;
    }

    private long activeScheduleId = 0;

    public void setScheduleId() {
        Map<String, String> params;
        params = FacesContext.getCurrentInstance().getExternalContext().getRequestParameterMap();

        String schId = params.get("scheduleId");
        LOGGER.debug("Schedule Id: " + schId);
        this.setActiveScheduleId(Long.parseLong(schId));
        LOGGER.debug("Schedule Id Assigned to Active Schedule Id.");
    }

    
    public String launchExam() {
        resetPercentageCounters();
        return launchGeneralExam();
    }
    
    public String launchGeneralExam() {
        LOGGER.debug("Inside LaunchExam");
        LOGGER.debug("Active Schedule Id: " + this.getActiveScheduleId());
        ExternalContext externalContext = FacesContext.getCurrentInstance().getExternalContext();
        getSob().setExamId(1);
        getSob().setExamType("General");
        getSob().setExamTimeLimit(900); // in seconds
        externalContext.getSessionMap().put("SESSION_OBJECT", getSob());
        this.getQuestionsForGeneralSession();

        setFormulaButtonDisabled(false);
        setReferOpenBookButtonDisabled(true);
        setReferRTTableButtonDisabled(false);

        initializeQuestionsForDisplay();

        return "questionBoard.xhtml?faces-redirect=true";
    }

    public String launchSpecificExam() {
        LOGGER.debug("Inside LaunchExam: Specific Exam");
        ExternalContext externalContext = FacesContext.getCurrentInstance().getExternalContext();
        getSob().setExamId(1);
        getSob().setExamType("Specific");
        getSob().setExamTimeLimit(720); // in seconds
        externalContext.getSessionMap().put("SESSION_OBJECT", getSob());
        this.getQuestionsForSpecificSession();

        setFormulaButtonDisabled(true);
        setReferOpenBookButtonDisabled(false);
        setReferRTTableButtonDisabled(false);

        initializeQuestionsForDisplay();

        return "questionBoard.xhtml?faces-redirect=true";
    }

    public String launchGeneralMockTest() {
        
        /**
         * Get Test Type
         */
        Map<String, String> params;
        params = FacesContext.getCurrentInstance().getExternalContext().getRequestParameterMap();

        String testId = params.get("testId");
        
        LOGGER.debug("Test Id: " + testId);
        /**
         * Typecast and set the selected test type id
         * and If test id is not equal to null, as in coming 
         * parameter is string we need to check for null condition
         * 
         * Here in this case, Test ID = 1, 1 -> General
         */
        if(testId != null)
            this.setTestId(Integer.parseInt(testId));
        
        LOGGER.debug("Inside LaunchMockTest: Launching General Test");
        ExternalContext externalContext = FacesContext.getCurrentInstance().getExternalContext();
        getSob().setExamId(2);
        getSob().setExamType("General Mock");
        getSob().setExamTimeLimit(900); // in seconds
        externalContext.getSessionMap().put("SESSION_OBJECT", getSob());
        this.getQuestionsForGeneralSession();

        /**
         * The following statements decide the nature of buttons on the tool
         * bar. Show Formula Button is enabled Refer Open Book Button is
         * disabled Refer RT Table Button is enabled
         */
        setFormulaButtonDisabled(false);
        setReferOpenBookButtonDisabled(true);
        setReferRTTableButtonDisabled(false);

        initializeQuestionsForDisplay();

        return "questionBoard.xhtml?faces-redirect=true";
    }

    public String launchSpecificMockTest() {
        /**
         * Get Test Type
         */
        Map<String, String> params;
        params = FacesContext.getCurrentInstance().getExternalContext().getRequestParameterMap();

        String testId = params.get("testId");
        
        LOGGER.debug("Test Id: " + testId);
        /**
         * Typecast and set the selected test type id
         * and If test id is not equal to null, as in coming 
         * parameter is string we need to check for null condition
         * 
         * Here in this case, Test ID = 2, 2 -> General
         */
        if(testId != null)
            this.setTestId(Integer.parseInt(testId));
        
        LOGGER.debug("Inside LaunchMockTest: Launching Specific Test");
        ExternalContext externalContext = FacesContext.getCurrentInstance().getExternalContext();
        getSob().setExamId(2);
        getSob().setExamType("Specific Mock");
        getSob().setExamTimeLimit(720); // in seconds
        externalContext.getSessionMap().put("SESSION_OBJECT", getSob());
        this.getQuestionsForSpecificSession();

        /**
         * The following statements decide the nature of buttons on the tool
         * bar. Show Formula Button is disabled Refer Open Book Button is
         * enabled Refer RT Table Button is enabled
         */
        setFormulaButtonDisabled(true);
        setReferOpenBookButtonDisabled(false);
        setReferRTTableButtonDisabled(false);

        initializeQuestionsForDisplay();

        return "questionBoard.xhtml?faces-redirect=true";
    }

    /**
     * @return the maxQuestionCount
     */
    public int getMaxQuestionCount() {
        return maxQuestionCount;
    }

    /**
     * @param maxQuestionCount the maxQuestionCount to set
     */
    public void setMaxQuestionCount(int maxQuestionCount) {
        this.maxQuestionCount = maxQuestionCount;
    }

    private void setTotalQuestionsCount() {
        /**
         * The size of the question arrived determines the total questions
         */
        this.setTotalQuestionsCount(this.getQuestionsList().size());

        /**
         * Set the maximum questions the a candidate need to answer. This
         * variable is required for internal calculations
         */
        this.setMaxQuestionCount(this.getQuestionsList().size());
    }

    private void setTotalUnansweredQuestionsCount() {
        /**
         * In the start always the un answered questions count is equal to total
         * questions
         */
        this.setUnAnsweredQuestionsCount(this.getMaxQuestionCount());
    }

    private void setTotalAnsweredQuestionsCount() {
        /**
         * In the start, always the answered question will be 0
         */
        this.setAttemptedAnswerCount(0);
    }

    private void setMarkedQuestionsForReviewCount() {
        /**
         * Initially the questions marked for reviews will be 0
         */
        this.setQuestionsMarkedForReview(0);
    }

    private void setCurrentQuestionPosition() {
        /**
         * Always set for the first time, set the question position to the first
         * record
         */
        this.setCurrentQuestion(this.questionsList.get(0));
    }

    public void restartTimer() {
        LOGGER.debug("................. Restarting the Timer .................");
    }

    private void initializeQuestionsForDisplay() {
        LOGGER.debug("Reinitializing All Variables...");

        setTotalQuestionsCount();
        setTotalUnansweredQuestionsCount();
        setTotalAnsweredQuestionsCount();
        setMarkedQuestionsForReviewCount();
        setCurrentQuestionPosition();
        resetTestSessionList();
        setPreviousButtonDisabled(true);
        setNextButtonDisabled(false);
        
    }

    private void resetTestSessionList() {
        this.testSessionList.clear();
    }

    /**
     * @return the backgroundColor
     */
    public String getBackgroundColor() {
        return backgroundColor;
    }

    /**
     * @param backgroundColor the backgroundColor to set
     */
    public void setBackgroundColor(String backgroundColor) {
        this.backgroundColor = backgroundColor;
    }

    private void markAsFailed() {

        LOGGER.debug("Inside markAsFailed Method:  Calling generateScheduleParamXML...");
        LOGGER.debug("*****************************************************************");
        LOGGER.debug("Total Percentage In General Exam:  " + getTotalPercentageInGeneralExam());
        LOGGER.debug("Total Percentage In Specific Exam:  " + getTotalPercentageInSpecificExam()); 
        LOGGER.debug("*****************************************************************");
        
        String inputXml = null;

        LOGGER.debug("Schedule Id: " + this.getActiveScheduleId());

        ExamScheduleParam examScheduleParam = new ExamScheduleParam();

        examScheduleParam.setScheduleId(this.getActiveScheduleId());
        examScheduleParam.setScheduleStatus(1);
        examScheduleParam.setUserId(sob.getUser().getUserId());

        inputXml = CreateXML.generateExamScheduleParamXML(examScheduleParam);
        LOGGER.debug(inputXml);

        WSCaller wsCaller = new WSCaller();

        try {

            UserEntitlement userEntitlement = wsCaller.callEditExamScheduleWS(URL.WS_URL_MARK_AS_FAILED, inputXml);
            LOGGER.debug("WS Update Message: " + userEntitlement.getUserDashboardDetail().getErrorMessage());

            this.getSob().setUserDashboardDetail(userEntitlement.getUserDashboardDetail());

        } catch (Exception ex) {
            LOGGER.debug(ex);
        }
    }

    private void markAsPassed() {

        LOGGER.debug("Inside markAsPassed Method:  Calling generateScheduleParamXML...");

        this.getSob().setR2ready(true);

        String inputXml = null;

        LOGGER.debug("Schedule Id: " + this.getActiveScheduleId());

        ExamScheduleParam examScheduleParam = new ExamScheduleParam();

        examScheduleParam.setScheduleId(this.getActiveScheduleId());
        examScheduleParam.setScheduleStatus(2);
        examScheduleParam.setUserId(sob.getUser().getUserId());

        inputXml = CreateXML.generateExamScheduleParamXML(examScheduleParam);
        LOGGER.debug(inputXml);

        WSCaller wsCaller = new WSCaller();

        try {

            UserEntitlement userEntitlement = wsCaller.callEditExamScheduleWS(URL.WS_URL_MARK_AS_PASSED, inputXml);
            LOGGER.debug("WS Update Message: " + userEntitlement.getUserDashboardDetail().getErrorMessage());

            this.getSob().setUserDashboardDetail(userEntitlement.getUserDashboardDetail());

        } catch (Exception ex) {
            LOGGER.debug(ex);
        }
    }

    /**
     * @return the activeScheduleId
     */
    public long getActiveScheduleId() {
        return activeScheduleId;
    }

    /**
     * @param activeScheduleId the activeScheduleId to set
     */
    public void setActiveScheduleId(long activeScheduleId) {
        this.activeScheduleId = activeScheduleId;
    }

    /**
     * @return the formulaButtonDisabled
     */
    public boolean isFormulaButtonDisabled() {
        return formulaButtonDisabled;
    }

    /**
     * @param formulaButtonDisabled the formulaButtonDisabled to set
     */
    public void setFormulaButtonDisabled(boolean formulaButtonDisabled) {
        this.formulaButtonDisabled = formulaButtonDisabled;
    }

    /**
     * @return the referRTTableButtonDisabled
     */
    public boolean isReferRTTableButtonDisabled() {
        return referRTTableButtonDisabled;
    }

    /**
     * @param referRTTableButtonDisabled the referRTTableButtonDisabled to set
     */
    public void setReferRTTableButtonDisabled(boolean referRTTableButtonDisabled) {
        this.referRTTableButtonDisabled = referRTTableButtonDisabled;
    }

    /**
     * @return the referOpenBookButtonDisabled
     */
    public boolean isReferOpenBookButtonDisabled() {
        return referOpenBookButtonDisabled;
    }

    /**
     * @param referOpenBookButtonDisabled the referOpenBookButtonDisabled to set
     */
    public void setReferOpenBookButtonDisabled(boolean referOpenBookButtonDisabled) {
        this.referOpenBookButtonDisabled = referOpenBookButtonDisabled;
    }

    /**
     * @return the nextButtonDisabled
     */
    public boolean isNextButtonDisabled() {
        return nextButtonDisabled;
    }

    /**
     * @param nextButtonDisabled the nextButtonDisabled to set
     */
    public void setNextButtonDisabled(boolean nextButtonDisabled) {
        this.nextButtonDisabled = nextButtonDisabled;
    }

    /**
     * @return the previousButtonDisabled
     */
    public boolean isPreviousButtonDisabled() {
        return previousButtonDisabled;
    }

    /**
     * @param previousButtonDisabled the previousButtonDisabled to set
     */
    public void setPreviousButtonDisabled(boolean previousButtonDisabled) {
        this.previousButtonDisabled = previousButtonDisabled;
    }

    /**
     * @return the totalPercentageInGeneralExam
     */
    public double getTotalPercentageInGeneralExam() {
        return totalPercentageInGeneralExam;
    }

    /**
     * @param totalPercentageInGeneralExam the totalPercentageInGeneralExam to
     * set
     */
    public void setTotalPercentageInGeneralExam(double totalPercentageInGeneralExam) {
        this.totalPercentageInGeneralExam = totalPercentageInGeneralExam;
    }

    /**
     * @return the totalPercentageInSpecificExam
     */
    public double getTotalPercentageInSpecificExam() {
        return totalPercentageInSpecificExam;
    }

    /**
     * @param totalPercentageInSpecificExam the totalPercentageInSpecificExam to
     * set
     */
    public void setTotalPercentageInSpecificExam(double totalPercentageInSpecificExam) {
        this.totalPercentageInSpecificExam = totalPercentageInSpecificExam;
    }

    /**
     * @return the totalAveragePercentage
     */
    public double getTotalAveragePercentage() {
        return totalAveragePercentage;
    }

    /**
     * @param totalAveragePercentage the totalAveragePercentage to set
     */
    public void setTotalAveragePercentage(double totalAveragePercentage) {
        this.totalAveragePercentage = totalAveragePercentage;
    }

    private void updateMockSession() {
        LOGGER.debug("Inside updateMockSession Method:  Calling generateScheduleParamXML...");

        resetPercentageCounters();

        int result = 0;
        double percenrageSecured = 0.0;
        
        setTotalPercentageInSpecificExam(getPercentageOfCorrectAnswers(this.getQuestionsList()));
        LOGGER.debug("--------------------------------------------------");
        LOGGER.debug("Total Percentage In General Exam:  " + getTotalPercentageInGeneralExam());
        LOGGER.debug("Total Percentage In Specific Exam:  " + getTotalPercentageInSpecificExam());
        LOGGER.debug("--------------------------------------------------");
        setTotalAveragePercentage((getTotalPercentageInGeneralExam() + getTotalPercentageInSpecificExam()) / 2);
        LOGGER.debug("Total Percentage from both exam: " + getTotalAveragePercentage());
        LOGGER.debug("--------------------------------------------------");

        LOGGER.debug("Afer Percentage Calculation");
        
        if(getTotalPercentageInGeneralExam() == 0){
            
            percenrageSecured = getTotalPercentageInSpecificExam();
            LOGGER.debug("General Exam is not taken");
            if(percenrageSecured> 70.0){
                result = 1;
            }
            //Set Percentage Secured
             
        }
        
        if(getTotalPercentageInSpecificExam() == 0){
            
            percenrageSecured = getTotalPercentageInSpecificExam();
            LOGGER.debug("Specific Exam is not taken");
            if(percenrageSecured> 70.0){
                result = 1;
            }
        }
        
        String inputXml = null;

        TestHistoryParam testHistoryParam = new TestHistoryParam();

        testHistoryParam.setUserId(sob.getUser().getUserId());
        testHistoryParam.setTestId(this.getTestId());
        testHistoryParam.setResult(result);
        testHistoryParam.setCreditPoint(1);
        testHistoryParam.setPercentageSecured(percenrageSecured);

        inputXml = CreateXML.generateTestHistoryParamXML(testHistoryParam);
        LOGGER.debug(inputXml);

        WSCaller wsCaller = new WSCaller();

        try {

            boolean wsCallStatus = wsCaller.callUpdateMockSessionWS(URL.WS_URS_UPDATE_MOCK_SESSION, inputXml);
            LOGGER.debug("Inside updateMockSession Method:  After WS Call... " + wsCallStatus);

        } catch (Exception ex) {
            LOGGER.debug(ex);
        }
    }

    private void resetPercentageCounters() {
        setTotalAveragePercentage(0.0);
        setTotalPercentageInGeneralExam(0.0);
        setTotalPercentageInSpecificExam(0.0);
    }

    /**
     * @return the testId
     */
    public int getTestId() {
        return testId;
    }

    /**
     * @param testId the testId to set
     */
    public void setTestId(int testId) {
        this.testId = testId;
    }
}
